import {
  Cell,
  type CellStyle,
  Graph,
  InternalEvent,
  xmlUtils,
  Codec,
  domUtils,
  utils,
  ModelXmlSerializer,
  FastOrganicLayout,
  Client,
  RubberBandHandler,
  ObjectCodec,
  CodecRegistry,
  EdgeHandler,
  gestureUtils,
  cellArrayUtils,
  Point,
  Geometry,
  ConnectionConstraint,
  PanningHandler,
  ConnectionHandler,
  CellState,
  constants,
  StyleRegistry,
  Perimeter,
  eventUtils,
  CellAttributeChange,
  EdgeStyle,
  SelectionHandler
} from "@maxgraph/core";
class JsonProperty {
  [prop: string]: any; // prop名字可以随便起
  constructor(option: any) {
    for (const key in option) {
      this[key] = option[key];
    }
  }
}
type CustomCell = Cell & {
  data?: JsonProperty;
};
export class SpiderEditor extends Graph {
  selectedCellListener: any;
  constructor(options: any) {
    if (Client.isBrowserSupported()) {
      super(options.element);
      this.selectedCellListener = options.selectedCellListener;
      const rootCell: any = this.getDataModel().getRoot();
      rootCell.data = new JsonProperty({
        spiderName: "未定义名称",
        "submit-strategy": "random",
        threadCount: ""
      });
      SelectionHandler.prototype.guidesEnabled = true;
      ConnectionHandler.prototype.movePreviewAway = false;
      // Enables guides
      EdgeHandler.prototype.snapToTerminals = true;
      this.setConnectable(true); // 是否允许Cells通过其中部的连接点新建连接,false则通过连接线连接
      new RubberBandHandler(this);
      this.setMultigraph(false);
      this.setTooltips(false); // 是否显示提示,默认显示Cell的名称
      this.setAllowLoops(false);
      this.setDropEnabled(true); // 从工具栏拖动到目标细胞时细胞边界是否产生光圈
      this.setEnabled(true); // 选择基本元素开启
      this.setCellsResizable(false); //节点不可改变大小
      this.getView().updateStyle = true; // 动态改变样式
      // this.panningHandler.useLeftButtonForPanning = true; // 设置左键可移动容器坐标轴
      this.setAutoSizeCells(true); // 鼠标拖动
      this.setPanning(false); // 移动镜头(移动容器坐标轴)
      this.setAllowDanglingEdges(false);
      this.setConnectableEdges(false);
      this.setDisconnectOnMove(false);
      this.extendParents = false;
      this.options.foldingEnabled = false;
      // this.setHtmlLabels(true)
      this.setCellsEditable(false); // 开启方块上的文字编辑功能
      this.registerJsonCodec();
      this.configureStylesheet();
      // this.isCellFoldable = () => false;
      // this.isPort = function (cell) {
      //   const geo = cell?.getGeometry();
      //   return geo?.relative ?? false;
      // };
      this.getTooltipForCell = function (cell) {
        return cell ? JSON.stringify(cell.style) : "Cell without dedicated style";
      };
      const self = this;
      this.addListener(InternalEvent.DOUBLE_CLICK, function () {
        self.onSelectedCell();
      });

      const panningHandler = this.getPlugin<PanningHandler>("PanningHandler");
      panningHandler.useLeftButtonForPanning = true;
      // panningHandler.ignoreCell = true;
      // 设置连线时的预览路径及样式
      const connectionHandler = this.getPlugin<ConnectionHandler>("ConnectionHandler");
      ConnectionHandler.prototype.outlineConnect = true;
      EdgeHandler.prototype.manageLabelHandle = true;
      EdgeHandler.prototype.outlineConnect = true;
      // mxGraphHandler.prototype.setMoveEnabled(false); //是否可以移动
      connectionHandler.setCreateTarget(true); //是否创建目标
      // handler.prototype.guidesEnabled = true;//显示细胞位置标尺
      // // Disables floating connections (only connections via ports allowed)
      EdgeHandler.prototype.isConnectableCell = function (cell) {
        return connectionHandler.isConnectableCell(cell);
      };
      // connectionHandler.createEdgeState = () => {
      //   // 设置预览的连接线,第三个参数为连接成功后连接线上的label
      //   const edge = this.createEdge(null, null as any, "连接线", null, null);
      //   console.log(111, edge);
      //   return new CellState(this.view, edge, this.getCellStyle(edge));
      // };
      connectionHandler.addListener(InternalEvent.CONNECT, (re: any, evt: any) => {
        const edge = evt.getProperty("cell");
        const jsonP = new JsonProperty({
          value: "连接线",
          "exception-flow": "0",
          lineWidth: "2",
          "line-style": "sharp",
          lineColor: "black",
          condition: "",
          "transmit-variable": "1"
        });
        // edge.value = "连接线";
        edge.data = jsonP;
        edge.setValue(jsonP.value);
        this.view?.refresh();
        // self.setSelectionCell(edge);
      });
    }
  }
  updateCellProperty(option: any) {
    const cell = this.getSelectedCell();
    this.batchUpdate(() => {
      cell.data = new JsonProperty(option);
      cell.setValue(option.value);
      this.view?.refresh();
    });
  }
  registerJsonCodec() {
    const codec = new ObjectCodec(new JsonProperty({}));
    codec.encode = function (enc, obj) {
      const node = enc.document.createElement("JsonProperty");
      domUtils.setTextContent(node, JSON.stringify(obj));
      return node;
    };
    codec.decode = function (_dec, node) {
      const obj = JSON.parse(domUtils.getTextContent(node as unknown as Text));
      obj.constructor = JsonProperty;
      return obj;
    };
    CodecRegistry.register(codec);
  }
  onSelectedCell() {
    this.selectedCellListener(this.getSelectedCell());
  }
  getSelectedCell() {
    const cell: any = this.getSelectionCell() || this.getDataModel().getRoot();
    cell.data = cell.data || new JsonProperty({});
    return cell;
  }
  setXml(xml: string) {
    const model = this.getDataModel();
    try {
      const modelXmlSerializer = new ModelXmlSerializer(model);
      modelXmlSerializer.import(xml);
    } catch (e) {
      console.error(e);
    } finally {
      model.endUpdate();
    }
  }

  getXml() {
    const xml = new ModelXmlSerializer(this.getDataModel()).export();
    return xml;
  }

  initToolbar(domToolbar: any) {
    if (!(domToolbar instanceof Array) || domToolbar.length <= 0) {
      return;
    }
    const parent = this.getDefaultParent();
    // const vertex = new Cell(null, new Geometry(0, 0, w, h), style);
    // vertex.setVertex(true);
    domToolbar.forEach((dom) => {
      const toolItemStr = dom.getAttribute("data-item");
      const toolItem = JSON.parse(toolItemStr);
      // const { width, height } = toolItem;
      const width = 32;
      const height = 32;
      const dropHandler = (graph: Graph, evt: MouseEvent) => {
        graph.stopEditing(false);
        const pt = graph.getPointForEvent(evt);
        const styleObj = {};
        const mergedObj = { ...styleObj, ...toolItem["style"] };
        graph.getDataModel().beginUpdate();
        try {
          const vertex: any = graph.insertVertex(
            parent,
            null,
            toolItem["template"] ? toolItem["template"].replace(/[\r\n]/g, "") : toolItem["title"],
            pt.x,
            pt.y,
            width,
            height,
            mergedObj
          ) as CustomCell;
          vertex.data = new JsonProperty(toolItem["option"]);
          graph.addCell(vertex, null);
          graph.setSelectionCell(vertex);
        } finally {
          graph.getDataModel().endUpdate();
        }
      };

      const createDragPreview = () => {
        const elt = document.createElement("div");
        elt.style.border = "2px dotted black";
        elt.style.width = `${width}px`;
        elt.style.height = `${height}px`;
        return elt;
      };
      gestureUtils.makeDraggable(dom, this, dropHandler, createDragPreview());
    });
  }
  deleteSelectCells() {
    const cells = this.getSelectionCells();
    this.removeCells(cells);
  }
  configureStylesheet() {
    // 设置节点的文字可被移动
    this.vertexLabelsMovable = false;
    const style = this.getStylesheet().getDefaultVertexStyle();
    style.shape = constants.SHAPE.IMAGE;
    style.rounded = true;
    style.perimeterSpacing = 6;
    style.verticalLabelPosition = constants.ALIGN.BOTTOM;
    // style.verticalAlign = constants.ALIGN.BOTTOM;
    // style.align = constants.ALIGN.CENTER;
    // style.imageAlign = constants.ALIGN.CENTER; // 图形水平方向对齐方式
    // style.spacingLeft = 0;
    // style.autoSize = true;
    style.spacingBottom = 0;
    // style.gradientColor = "#7d85df";
    // style.strokeColor = "#05c6e5";
    // style.fillColor = "#adc5ff";
    // style.fontColor = "#1d258f";
    // style.strokeWidth = 2;
    // style.fontFamily = "Verdana";
    // style.fontSize = 10;
    // style.fontStyle = 0;
    // style.opacity = 100;
    // style.shadow = true;
    // style.imageWidth = 20;
    // style.imageHeight = 20;
    // style.spacing = 16;
    // style.perimeter = Perimeter.EllipsePerimeter;
    this.getStylesheet().putDefaultVertexStyle(style);

    const edgeStyle = this.getStylesheet().getDefaultEdgeStyle();
    edgeStyle.edgeStyle = constants.EDGESTYLE.ORTHOGONAL;
    // edgeStyle.edgeStyle = "orthogonalEdgeStyle";
    edgeStyle.indicatorColor = "#99ccff";
    edgeStyle.strokeColor = "blue";
    edgeStyle.indicatorWidth = 4;
    edgeStyle.strokeWidth = 2;
    edgeStyle.endSize = 2;
    // edgeStyle.entryPerimeter = true;
    // edgeStyle.entryY = 0;
    // edgeStyle.entryX = 0;
    edgeStyle.rounded = true;
    this.getStylesheet().putDefaultEdgeStyle(edgeStyle);
    // edgeStyle.labelBackgroundColor = "#FFFFFF";
    // edgeStyle.edgeStyle = EdgeStyle.ElbowConnector;
  }
}
